-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Defer tail call ret ty equality to check_tail_calls #144915
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Defer tail call ret ty equality to check_tail_calls #144915
Conversation
|
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
@@ -1931,7 +1931,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | |||
self.tcx(), | |||
self.infcx.typing_env(self.infcx.param_env), | |||
) { | |||
span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't the point here that the function does not diverge (as its return type is not uninhabited), but we don't have a dest?
as in, the comment was correct
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm... i think i see, but in that case i would call it non-diverging
@@ -118,21 +118,7 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> { | |||
} | |||
|
|||
if caller_sig.inputs_and_output != callee_sig.inputs_and_output { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please also add a test that we anonymize bound vars: for<'a> fn(&'a ())
and for<'b> fn(&'b ())
r? lcnr r=me after nits |
That doesn't seem to track for me 🤔 The only reason we care about signature equality is that we need ABIs to match exactly, but ABIs are completely unaffected by lifetimes, so for the purpose of lifetimes we can do the same as normal call+ret. |
// FIXME(explicit_tail_calls): this currently fails for cases where opaques are used. | ||
// e.g. | ||
// ``` | ||
// fn a() -> impl Sized { become b() } // ICE | ||
// fn b() -> u8 { 0 } | ||
// ``` | ||
// we should think what is the expected behavior here. | ||
// (we should probably just accept this by revealing opaques?) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you keep this fixme? (it doesn't ICE anymore, but doesn't work either...)
= note: caller signature: `fn() -> for<'a> fn(&'a i32)` | ||
= note: callee signature: `fn() -> fn(&i32)` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we not printing 'static
? This looks so confusing 😵💫
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because we erase regions. We could print the unerased signature, but this has nothing to do with static, and it is a preexisting issue with args.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
preexisting example:
#![feature(explicit_tail_calls)]
#![allow(incomplete_features)]
fn foo<'a>(_: fn(&'a ())) {
become bar(dummy);
}
fn bar(_: fn(&())) {}
fn dummy(_: &()) {}
fn main() {}
error: mismatched signatures
--> src/main.rs:5:5
|
5 | become bar(dummy);
| ^^^^^^^^^^^^^^^^^
|
= note: `become` requires caller and callee to have matching signatures
= note: caller signature: `fn(fn(&()))`
= note: callee signature: `fn(for<'a> fn(&'a ()))`
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've opened #144957 so that we don't forget to return to this at some point
They are affected by higher-ranked lifetimes, though, and higher-ranked subtyping is different than higher-ranked equality. So what I'm saying is that checking this the way that normal return types are checked is (theoretically) insufficient since they don't enforce return type equality, but just a subtyping relationship between the thing being returned by the callee and the thing being returned by the caller. That being said, do we even have a case where a non-invariant arg causes a struct or something to have a different layout so that a subtyping operation would change its layout? |
A type and its subtype always has the same layout and ABI, since |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks like a reasonable step. r=us with nits
if caller_sig.output() != callee_sig.output() { | ||
span_bug!(expr.span, "hir typeck should have checked the return type already"); | ||
} | ||
self.report_arguments_mismatch(expr.span, caller_sig, callee_sig); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: the function should probably be renamed to report_signature_mismatch
Fixes #144892.
Currently the tail call signature check assumes that return types have been accounted for. However, this is not complete for several reasons.
Firstly, we were using subtyping instead of equality in the HIR typeck code:
rust/compiler/rustc_hir_typeck/src/expr.rs
Line 1096 in e1b9081
We could fix this, but it doesn't really do much for us anyways since HIR typeck doesn't care about regions.
That means, secondly, we'd need to fix the terminator type check in MIR typeck to account for variances, since tail call terminators need to relate their arguments invariantly to account for the "signature must be equal" rule. This seems annoying.
All of this seems like a lot of work, and we already are manually checking argument equality. Let's just extend the
check_tail_calls
to account for mismatches in return types anyways.r? @WaffleLapkin